package cn.jbolt.core.gen;

import cn.hutool.core.util.ArrayUtil;
import cn.jbolt.core.base.JBoltIDGenMode;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Model;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

/**
 * JBolt项目生成器配置
 *
 * @ClassName: JBoltProjectGenConfig
 * @author: JFinal学院-小木 QQ：909854136
 * @date: 2019年12月10日
 */
public class JBoltProjectGenConfig {
	public static final String SEPARATOR = File.separator;
	public static String projectRootPath = System.getProperty("user.dir");
	public static final String projectType = "maven";// 项目类型 normalormaven
	public static String dbType = null;// 数据库类型 需要读取文件
	public static String idGenMode = JBoltIDGenMode.AUTO;// 默认主键生成模式
	public static String jdbcUrl = null;// jdbcURl 需要读取文件
	public static String user = null;// 数据库用户名
	public static String password = null;// 数据库密码
	public static boolean genModel = true;// 是否生成model和baseModel
	public static final boolean generateDaoInModel = false;// 是否dao生成在Model中
	public static final boolean generateChainSetterInBaseModel = true;
	public static boolean generateHtmlDataDictionary = true;// 是否生成JFinal默认的html格式数据字典
	public static String removedTableNamePrefixes = "jb_";// 生成的Model 去掉前缀
	public static final boolean charToBoolean = true;// 生成时 char(1)转Boolean
	public static final boolean baseModelExtendsJBoltBaseModel = true;// 继承JBoltBaseModel
	public static String modelPackageName = "cn.jbolt.common.model";// model生成的包
	public static String baseModelPackageName = null;// basemodel生成的包
	public static String modelOutputDir = null;// model输出路径
	public static String baseModelOutputDir = null;// base model输出路径
	public static boolean genJBoltCoreModel = false;// 是否生成JBolt核心表
	public static JBoltColumnToBuildAttrNameFunction columnTobuildAttrNameFun;
	public static String[] tableNames = null;// 单次生成直接指定需要生成的表名 与 tableNamePrefixes 互斥
	public static String[] tableNamePrefixes = null;// 单次生成直接指定需要生成的表名前缀 依据前缀过滤 不带前缀的不生成 与tableNames 互斥

	//是否开始启动缓存机制 开启后会在Model上生成@JBoltAutoCache注解
	public static boolean autoCacheEnable = false;
	//是否开启idCache策略
	public static boolean idCacheEnable = true;
	//是否开启KeyCache策略
	public static boolean keyCacheEnable = false;
	//KeyCache 使用哪个字段属性
	public static String keyCacheColumn = "";
	//KeyCache 还需额外绑定哪个属性
	public static String keyCacheBindColumn = "";
	//是否开启数据库视图生成
	public static boolean generateView = false;
	//是否强制覆盖掉现存model 默认不覆盖model 只覆盖baseModel
	public static boolean cover = false;
	//字段翻译设置
	public static List<? extends Model<?>> translates = null;
	//是否baseModel生成的静态常量
	public static boolean genColConstant = true;
	//baseModel生成的静态常量全部最大化
	public static boolean genColConstantToUpperCase = true;

	/**
	 * 设置自动缓存策略
	 * @param autoCacheEnable
	 * @param idCacheEnable
	 * @param keyCacheEnable
	 * @param keyCacheColumn
	 * @param keyCacheBindColumn
	 */
	public static void setModelAutoCache(boolean autoCacheEnable,boolean idCacheEnable,boolean keyCacheEnable,String keyCacheColumn,String keyCacheBindColumn){
		if(autoCacheEnable && !idCacheEnable && !keyCacheEnable){
			throw new RuntimeException("autoCache开启，必须指定至少一种策略idCache、keyCache或者都开");
		}
		if(autoCacheEnable && keyCacheEnable && StrKit.isBlank(keyCacheColumn)){
			throw new RuntimeException("JBoltAutoCache keyCache开启后必须设置keyCacheColumn 指定使用哪一列属性作为Cache Key");
		}
		JBoltProjectGenConfig.autoCacheEnable = autoCacheEnable;
		JBoltProjectGenConfig.idCacheEnable = idCacheEnable;
		JBoltProjectGenConfig.keyCacheEnable = keyCacheEnable;
		JBoltProjectGenConfig.keyCacheColumn = keyCacheColumn;
		JBoltProjectGenConfig.keyCacheBindColumn = keyCacheBindColumn;
	}

	/**
	 * 初始化项目model生成配置
	 * @param projectRootPath
	 * @param modelPackageName
	 * @param genModel
	 * @param idGenMode
	 * @param genHtmlDataDictionary
	 * @param genJBoltCoreModel
	 * @param removedTableNamePrefixes
	 * @param columnTobuildAttrNameFun
	 * @param tableNames
	 * @param tableNamePrefixes
	 * @param generateView
	 * @param cover
	 */
	public static void init(String projectRootPath, String modelPackageName, boolean genModel, String idGenMode,
							boolean genHtmlDataDictionary, boolean genJBoltCoreModel, String removedTableNamePrefixes,
							JBoltColumnToBuildAttrNameFunction columnTobuildAttrNameFun, String[] tableNames, String[] tableNamePrefixes, boolean generateView, List<? extends Model<?>> translates, boolean cover) {
		if (tableNames != null && tableNames.length > 0 && tableNamePrefixes != null && tableNamePrefixes.length > 0) {
			throw new RuntimeException("tableNames 与 tableNamePrefixes 互斥关系 只能选择一个");
		}
		JBoltProjectGenConfig.projectRootPath = projectRootPath;
		JBoltProjectGenConfig.modelPackageName = modelPackageName;
		modelOutputDir = projectRootPath + SEPARATOR + "src" + SEPARATOR + "main" + SEPARATOR + "java" + SEPARATOR
				+ modelPackageName.replace(".", SEPARATOR);
		baseModelPackageName = modelPackageName + ".base";
		baseModelOutputDir = modelOutputDir + SEPARATOR + "base";
		if (StrKit.isBlank(idGenMode)) {
			idGenMode = JBoltIDGenMode.AUTO;
		}
		JBoltProjectGenConfig.idGenMode = idGenMode;
		JBoltProjectGenConfig.genModel = genModel;
		JBoltProjectGenConfig.generateHtmlDataDictionary = genHtmlDataDictionary;
		JBoltProjectGenConfig.genJBoltCoreModel = genJBoltCoreModel;
		JBoltProjectGenConfig.translates = translates;
		JBoltProjectGenConfig.cover = cover;
		if (StrKit.notBlank(removedTableNamePrefixes)) {
			JBoltProjectGenConfig.removedTableNamePrefixes = JBoltProjectGenConfig.removedTableNamePrefixes + ","
					+ removedTableNamePrefixes;
		}
		if (columnTobuildAttrNameFun != null) {
			JBoltProjectGenConfig.columnTobuildAttrNameFun = columnTobuildAttrNameFun;
		}

		if (tableNames != null && tableNames.length > 0) {
			JBoltProjectGenConfig.tableNames = tableNames;
		}
		if (tableNamePrefixes != null && tableNamePrefixes.length > 0) {
			JBoltProjectGenConfig.tableNamePrefixes = tableNamePrefixes;
		}

		JBoltProjectGenConfig.generateView = generateView;

		tableNamesPatterns.add("jb_.+_+[0-9]+");
		tableNamesIndexOfList.add("sqlite_");
		tableNamesIndexOfList.add("_old_");

		filterTableNames.add("dept");
		filterTableNames.add("emp");
		filterTableNames.add("salgrade");
		filterTableNames.add("bonus");
		filterTableNames.add("dtproperties");
	}

	/**
	 * 过滤规则
	 */
	public static Predicate<String> tableSkipPredicate = new Predicate<String>() {
		@Override
		public boolean test(String tableName) {
			tableName = tableName.toLowerCase();
			//不在指定名字的就跳过
			if (tableNames != null && tableNames.length > 0) {
				return !ArrayUtil.containsIgnoreCase(tableNames, tableName);
			}
			//设置不生成核心表 而且前缀是核心表前缀的话 就跳过
			if (!genJBoltCoreModel && tableName.startsWith("jb_")) {
				return true;
			}
			//满足包含字符串 指定不生表 满足不生成正则的 都跳过
			boolean skip = tableNamesInFiterList(tableName) || tableNamesIndexOf(tableName) || tableNamesMatch(tableName);
			if(skip) {
				return true;
			}
			//指定了只生成前缀的 看看是否存在 不存在就跳过
			if (tableNamePrefixes != null && tableNamePrefixes.length > 0) {
				boolean exists = false;
				for(String pr:tableNamePrefixes) {
					exists = tableName.startsWith(pr);
					if(exists){
						break;
					}
				}
				return !exists;
			}
			//最后不跳过
			return false;

		}
	};

	/**
	 * 初始化数据库配置
	 *
	 * @param dbType
	 * @param jdbcUrl
	 * @param user
	 * @param password
	 */
	public static void setDbConfig(String dbType, String jdbcUrl, String user, String password) {
		JBoltProjectGenConfig.dbType = dbType;
		JBoltProjectGenConfig.jdbcUrl = jdbcUrl;
		JBoltProjectGenConfig.user = user;
		JBoltProjectGenConfig.password = password;
	}

	/**
	 * 判断表名是否包含指定自定义字符串
	 *
	 * @param tableName
	 * @return
	 */
	public static boolean tableNamesIndexOf(String tableName) {
		boolean in = false;
		for (String str : tableNamesIndexOfList) {
			if (tableName.contains(str)) {
				in = true;
				break;
			}
		}
		return in;
	}

	/**
	 * 判断表名符合正则
	 *
	 * @param tableName
	 * @return
	 */
	public static boolean tableNamesMatch(String tableName) {
		boolean in = false;
		for (String p : tableNamesPatterns) {
			if (tableName.matches(p)) {
				in = true;
				break;
			}
		}
		return in;
	}

	/**
	 * 判断是否在完整过滤表名中存在
	 *
	 * @param tableName
	 * @return
	 */
	public static boolean tableNamesInFiterList(String tableName) {
		return filterTableNames.contains(tableName)||filterTableNames.contains(tableName.toLowerCase())||filterTableNames.contains(tableName.toUpperCase());
	}

	/**
	 * 不需要生成的表名（全部小写），直接完整的表名，一般都是一些数据库内置表什么的 这里默认给了几个，需要的自己加
	 */
	private static List<String> filterTableNames = new ArrayList<String>();
	/**
	 * 这里是判断表名中有包含以下字符串的需要过滤掉 一些分表不需要生成 例如jb_wechat_user_ 一些sqlite中的临时表和内置不需要
	 */
	private static List<String> tableNamesIndexOfList = new ArrayList<String>();
	/**
	 * 这里是判断表名符合的正则表达式
	 */
	private static List<String> tableNamesPatterns = new ArrayList<String>();

	/**
	 * 添加不生成的表名
	 * @param tables
	 */
	public static void addDontGenTableNames(String... tables) {
		if(tables!=null&&tables.length>0) {
			for(String t:tables) {
				filterTableNames.add(t);
			}
		}
	}


	/**
	 * 添加指定的表名里包含指定字符串的不生成
	 * @param strs
	 */
	public static void addDontGenTableNamesIndexOfStr(String... strs) {
		if(strs!=null&&strs.length>0) {
			for(String t:strs) {
				tableNamesIndexOfList.add(t);
			}
		}
	}

	/**
	 * 添加不生成的分表前缀 格式是  前缀_字符串_数字
	 * @param prefixes
	 */
	public static void addDontGenSeparateTableNamePrefixe(String... prefixes) {
		if(prefixes!=null&&prefixes.length>0) {
			for(String p:prefixes) {
				tableNamesPatterns.add(p+".+_+[0-9]+");
			}
		}
	}
	/**
	 * 添加不生成的表名正则
	 * @param patterns
	 */
	public static void addDontGenTableNamesPatterns(String... patterns) {
		if(patterns!=null&&patterns.length>0) {
			for(String p:patterns) {
				tableNamesPatterns.add(p);
			}
		}
	}
}
